package com.gollum.config;

import com.gollum.web.security.filter.JwtTokenAuthFilter;
import com.gollum.web.security.handler.LogoutSuccessHandler;
import com.gollum.web.security.handler.UnAuthorizedHandler;
import com.gollum.web.service.UserDetailsServiceimpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;


/**
 * springSecurity配置
 *
 * @author Herther
 * @version 1.0.0
 * @createTime 2022年08月23日 22:26:00
 */
@SuppressWarnings("ALL")
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) /** 开启注解校验  启用方法级别的权限认证**/
@Configuration
@EnableWebSecurity	// 添加 security 过滤器
@Lazy //解决启动慢问题
public class SpringSecurityConfig  {

    @Autowired
    protected UnAuthorizedHandler unAuthorizedHandler;




    /**
     * token认证过滤器
     */
    @Autowired
    protected JwtTokenAuthFilter authFilter;

    @Autowired
    protected LogoutSuccessHandler logoutSuccessHandler;

    @Autowired
    protected CorsFilter corsFilter;

    @Autowired
    protected UserDetailsServiceimpl userDetailsService;


    /** swagger 忽略 **/
    private final String[] ignoreUrl = {"/swagger-ui.html","/webjars/**","/*/api-docs","/druid/**","/doc.html","/swagger-resources/**"};
    /** 系统相关 忽略 **/
    private final String[] ignoreCompUrl = {"/thread/**"};
    /** 认证相关 忽略 **/
    private final String[] ignoreUrlAuthUrl = {"/auth/login","/register","/auth/code","/auth/check"};

    /**
     * anyRequest          |   匹配所有请求路径
     * access              |   SpringEl表达式结果为true时可以访问
     * anonymous           |   匿名可以访问
     * denyAll             |   用户不能访问
     * fullyAuthenticated  |   用户完全认证可以访问（非remember-me下自动登录）
     * hasAnyAuthority     |   如果有参数，参数表示权限，则其中任何一个权限可以访问
     * hasAnyRole          |   如果有参数，参数表示角色，则其中任何一个角色可以访问
     * hasAuthority        |   如果有参数，参数表示权限，则其权限可以访问
     * hasIpAddress        |   如果有参数，参数表示IP地址，如果用户IP和参数匹配，则可以访问
     * hasRole             |   如果有参数，参数表示角色，则其角色可以访问
     * permitAll           |   用户可以任意访问
     * rememberMe          |   允许通过remember-me登录的用户访问
     * authenticated       |   用户登录后可访问
     */
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http
                //禁用csrf
                .csrf().disable()
                // 认证失败处理类
                .exceptionHandling().authenticationEntryPoint(unAuthorizedHandler).and()
                // 基于token，所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                //静态资源
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                //swagger
                .antMatchers(ignoreUrl).permitAll()
                //登录注册认证
                .antMatchers(ignoreUrlAuthUrl).permitAll()
                //系统相关
                .antMatchers(ignoreCompUrl).permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                .and()
                .formLogin().disable()
                //不需要form表单
                .headers().frameOptions().disable()
                .and()
                // 添加JWT filter
                .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
                //添加退出登录 filter
                .logout().logoutUrl("/auth/logout").logoutSuccessHandler(logoutSuccessHandler).and()
                //添加CORS filter
                .addFilterBefore(corsFilter, JwtTokenAuthFilter.class)
                .addFilterBefore(corsFilter, LogoutFilter.class)
                //自定义登录授权
                .userDetailsService(userDetailsService)
                .build();
    }

    /**
     * 获取AuthenticationManager（认证管理器），登录时认证使用
     *
     * @auther: Herther
     * @version 1.0.0
     * @date: 2022/8/27 22:56
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * 使用SpringSecurity 强散列哈希加密实现
     *
     * @auther: Herther
     * @version 1.0.0
     * @date: 2022/8/23 23:54
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
